﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel.Design;
using DevelopStudio.Common.Basic;

namespace AccountFormsCtrlLib
{
    [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
    public partial class ListControlView : UserControl
    {
        List<ControlBase> m_myControls;

        private int TotalControlHeight = 0;
        private int initilzeControlNum = 0;

        private int selectIndex = -1;
        private int lastSelectIndex = -1;
        public event System.EventHandler SelectedIndexChanged;
        public event System.EventHandler DragDrop;
        public event System.EventHandler ControlCountChanged;
        private List<int> IndexVisibleList = new List<int>();
        private bool bAddFromFirstorEnd = true;
        private int LastDragY = 0;
        ControlBase lastDragOver;
        private int DragIndex = 0;
        private int LeftOffset = 0;
        private bool lastScrollbarVisiable;
        private int lastScrollbarHeight;

        public List<ControlBase> ListControls
        {
            get
            {
                return m_myControls;
            }
        }

        public bool AddFromFirst
        {
            get
            {
                return bAddFromFirstorEnd;
            }
            set
            {
                bAddFromFirstorEnd = value;
            }
        }

        public ListControlView()
        {
            InitializeComponent();
            m_myControls = new List<ControlBase>();
            initilzeControlNum = Controls.Count;
            vScrollBarAdv1.Visible = true;

            this.vScrollBarAdv1.Minimum = 0;
            this.vScrollBarAdv1.Maximum = 0;
            this.vScrollBarAdv1.LargeChange = 60;
            this.vScrollBarAdv1.SmallChange = 10;
            this.vScrollBarAdv1.Focus();

            this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
            this.UpdateStyles(); 
        }

        public int Count
        {
            get
            {
                return ListControls.Count;
            }
        }

        public int SelectIndex
        {
            get
            {
                return selectIndex;
            }

            set
            {
                lastSelectIndex = selectIndex;
                selectIndex = value;
                OnSelectIndexChanged();
            }
        }

        public int LastSelectIndex
        {
            get
            {
                return lastSelectIndex;
            }
        }

        private void OnSelectIndexChanged() 
        {
            DoSelectAction();
            if (SelectedIndexChanged != null)
            {
                if ((SelectIndex >= 0) && (SelectIndex < ListControls.Count))
                {
                    SelectedIndexChanged(ListControls[selectIndex], null);
                }
            }
        }

        private void OnDragDrop()
        {
            if (DragDrop != null)
            {
                DragDrop(ListControls[selectIndex], null);
            }
        }

        public void DoSelectAction()
        {
            if ((LastSelectIndex >= 0) && (LastSelectIndex < ListControls.Count))
            {
                ListControls[LastSelectIndex].DeleteBorderForNoSelect();
            }

            if ((SelectIndex >= 0) && (SelectIndex < ListControls.Count))
            {
                ListControls[SelectIndex].ShowBorderForSelect();
            }
        }

        public void Add(ControlBase value)
        {
            value.Size = new Size(this.vScrollBarAdv1.Visible == false ? this.Size.Width : this.Size.Width - this.vScrollBarAdv1.ClientSize.Width, value.Height);
            value.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;
            value.AllowDrop = true;
            value.MouseDown += this.Controls_MouseDown;
            value.QueryContinueDrag += this.Controls_QueryContinueDrag;
            value.DragOver += this.Controls_DragOver;
            value.DragLeave += Controls_DragLeave;
            value.DragDrop += Controls_DragDrop;
            value.ExpandedChanged += Controls_ExpandedChanged;
            value.DisplayChanged += Controls_DisplayChanged;
            Controls.Add(value);

            if (AddFromFirst)
            {
                PlaceAddFromFirst(value);
            }
            else
            {
                PlaceAddFromEnd(value);
            }

            if (this.ControlCountChanged != null)
            {
                this.ControlCountChanged(this, new EventArgs());
            }
        }

        private void Controls_DisplayChanged(object sender, StatusEventArgs e)
        {
            if ((bool)e.NewStatus == true)
            {
                this.Remove(sender as ControlBase);
            }
        }

        private void Controls_ExpandedChanged(object sender, ExpandedChangeEventArgsEx e)
        {
            ControlBase control = sender as ControlBase;

            if (control == null)
            {
                return;
            }

            int index = this.ListControls.FindIndex(o => o == control);

            if (index == -1)
            {
                return;
            }

            int offset = e.NewExpandedValue == true ? e.SizeOffset : e.SizeOffset * (-1);

            this.UpdateScrollBar(offset, index == (this.ListControls.Count - 1));

            ShowContent();
        }

        private void UpdateScrollBar(int offset, bool lastOneControl, bool resize = false)
        {
            int lastTotalHeight = TotalControlHeight;

            if (resize == false)
            {
                TotalControlHeight += offset;
            }

            if (TotalControlHeight > vScrollBarAdv1.ClientSize.Height)
            {
                vScrollBarAdv1.Visible = true;

                int lastvalueMax = this.vScrollBarAdv1.Maximum;
                int lastValue = this.vScrollBarAdv1.Value;

                int lastheightdiff = lastTotalHeight - this.vScrollBarAdv1.ClientSize.Height;
                int heightdiff = TotalControlHeight - this.vScrollBarAdv1.ClientSize.Height;

                int currentMax = (int)((double)(TotalControlHeight * vScrollBarAdv1.LargeChange) / (double)vScrollBarAdv1.ClientSize.Height);

                if (currentMax < 0)
                {
                    this.vScrollBarAdv1.Maximum = 0;
                }
                else
                {
                    this.vScrollBarAdv1.Maximum = currentMax;
                }


                if (lastOneControl == true)
                {
                    this.vScrollBarAdv1.Value = vScrollBarAdv1.Maximum;
                }
                else
                {
                    int currentvalue;

                    if (lastValue < 0)
                    {
                        currentvalue = 0;
                    }
                    else
                    {
                        currentvalue = (int)((double)(lastheightdiff * currentMax * lastValue) / (lastvalueMax * heightdiff));
                    }

                    if (currentvalue < 0)
                    {
                        this.vScrollBarAdv1.Value = 0;
                    }
                    else if (currentvalue > this.vScrollBarAdv1.Maximum)
                    {
                        this.vScrollBarAdv1.Value = this.vScrollBarAdv1.Maximum;
                    }
                    else
                    {
                        this.vScrollBarAdv1.Value = currentvalue;
                    }
                }
            }
            else
            {
                this.vScrollBarAdv1.Maximum = 0;
                this.vScrollBarAdv1.Value = 0;

                vScrollBarAdv1.Visible = false;
            }
        }

        void Controls_DragDrop(object sender, DragEventArgs e)
        {
            //Console.Write("Controls_DragDrop\n");
            int iCnt = 0;
            ControlBase SelectControl = ListControls[SelectIndex];
            if (SelectIndex > DragIndex)
            {
                for (iCnt = SelectIndex - 1; iCnt >= DragIndex; --iCnt)
                {
                    ListControls[iCnt].Location = new Point(this.LeftOffset, ListControls[iCnt].Location.Y + SelectControl.Size.Height);
                    ListControls[iCnt + 1] = ListControls[iCnt];
                }
                ListControls[DragIndex] = SelectControl;
                SelectIndex = DragIndex;
            }
            else if (SelectIndex < DragIndex)
            {
                for (iCnt = SelectIndex + 1; iCnt <= DragIndex; ++iCnt)
                {
                    ListControls[iCnt].Location = new Point(this.LeftOffset, ListControls[iCnt].Location.Y - SelectControl.Size.Height);
                    ListControls[iCnt - 1] = ListControls[iCnt];
                }
                ListControls[DragIndex] = SelectControl;
                SelectIndex = DragIndex;
            }
            else {

            }
        }

        void Controls_DragLeave(object sender, EventArgs e)
        {
            //Console.Write("Controls_DragLeave\n");
            if(ListControls[SelectIndex] != ((ControlBase)sender))
            {
                ((ControlBase)sender).ShowBorderForDragLeave();
            }
        }

        void Controls_DragOver(object sender, DragEventArgs e)
        {
            //Console.Write("Controls_DragOver\n");
            ControlBase myCtrl = (ControlBase)sender;
            ControlBase myDragCtrl = ListControls[SelectIndex];

            DragIndex = ListControls.IndexOf(myCtrl);

            if (myCtrl != myDragCtrl)
            {
                if (LastDragY < e.Y)
                {
                    ((ControlBase)sender).ShowBorderForDragOver(DevComponents.DotNetBar.eBorderSide.Bottom);
                    ++DragIndex;
                }
                else if (LastDragY > e.Y)
                {
                    ((ControlBase)sender).ShowBorderForDragOver(DevComponents.DotNetBar.eBorderSide.Top);
                }
            }

            LastDragY = e.Y;
            lastDragOver = myCtrl;
        }

        void Controls_MouseDown(object sender, MouseEventArgs e)
        {
            //Console.Write("Controls_MouseDown\n");
            foreach (int Index in IndexVisibleList)
            {
                if (ListControls[Index] == (ControlBase)sender)
                {
                    SelectIndex = Index;
                    break;
                }
            }
            DragIndex = SelectIndex;
            lastDragOver = ((ControlBase)sender);
            if (this.ContextMenu != null)
            {
                this.ContextMenu.Show(lastDragOver, e.Location);
            }
            if (e.Button == MouseButtons.Left)
            {
                ((ControlBase)sender).DoDragDrop("", DragDropEffects.Copy | DragDropEffects.None);
            }

            this.Cursor = System.Windows.Forms.Cursors.Default;
        }

        private void Controls_QueryContinueDrag(object sender, System.Windows.Forms.QueryContinueDragEventArgs e)
        {
            //Console.Write("Controls_QueryContinueDrag\n");
            if (e.Action == DragAction.Continue)
            {
                //Console.Write("Continue\n");
                if ((lastDragOver.Location.Y <= 0) & (vScrollBarAdv1.Value > 0))
                {
                    vScrollBarAdv1.Value -= 1;
                    this.Cursor = System.Windows.Forms.Cursors.NoMoveVert;
                    ShowContent();
                    this.Cursor = System.Windows.Forms.Cursors.Default;
                }
                else if ((lastDragOver.Location.Y + lastDragOver.Size.Height >= vScrollBarAdv1.ClientSize.Height)
                    && (vScrollBarAdv1.Value < (vScrollBarAdv1.Maximum - vScrollBarAdv1.LargeChange + 1)))
                {
                    vScrollBarAdv1.Value += 1;
                    this.Cursor = System.Windows.Forms.Cursors.NoMoveVert;
                    ShowContent();
                    this.Cursor = System.Windows.Forms.Cursors.Default;
                }
            }
            else if (e.Action == DragAction.Drop)
            {
                int iCnt = 0;
                ControlBase SelectControl = ListControls[SelectIndex];
                Point DragPoint = ListControls[DragIndex].Location;
                if (SelectIndex > DragIndex)
                {
                    
                    for (iCnt = SelectIndex - 1; iCnt >= DragIndex; --iCnt)
                    {
                        if (ListControls[iCnt].Visible == true)
                        {
                            ListControls[iCnt].Location = new Point(this.LeftOffset, ListControls[iCnt].Location.Y + SelectControl.Size.Height);

                        }
                        ListControls[iCnt + 1] = ListControls[iCnt];
                    }
                    SelectControl.Location = DragPoint;
                    EnableControl(SelectControl);
                    ListControls[DragIndex] = SelectControl;
                    SelectIndex = DragIndex;
                    OnDragDrop();
                }
                else if (SelectIndex < DragIndex)
                {
                    for (iCnt = SelectIndex + 1; iCnt <= DragIndex; ++iCnt)
                    {
                        if (ListControls[iCnt].Visible == true)
                        {
                            ListControls[iCnt].Location = new Point(this.LeftOffset, ListControls[iCnt].Location.Y - SelectControl.Size.Height);
                        }
                        ListControls[iCnt - 1] = ListControls[iCnt];
                    }
                    SelectControl.Location = DragPoint;
                    EnableControl(SelectControl);
                    ListControls[DragIndex] = SelectControl;
                    SelectIndex = DragIndex;
                    OnDragDrop();
                }
                else
                {

                }
            }
            else 
            {

            }
            this.Cursor = System.Windows.Forms.Cursors.Default;
            Update();
            if (e.EscapePressed)
            {
                e.Action = DragAction.Cancel;
            }
        }

        private void RemoveControl(ControlBase control)
        {
            control.MouseDown -= this.Controls_MouseDown;
            control.QueryContinueDrag -= this.Controls_QueryContinueDrag;
            control.DragOver -= this.Controls_DragOver;
            control.DragLeave -= Controls_DragLeave;
            control.DragDrop -= Controls_DragDrop;
            control.ExpandedChanged -= Controls_ExpandedChanged;
            control.DisplayChanged -= Controls_DisplayChanged;
            Controls.Remove(control);
        }

        public void RemoveAll()
        {
            foreach (ControlBase control in ListControls)
            {
                this.RemoveControl(control);
            }
            ListControls.Clear();
            this.TotalControlHeight = 0;
            this.lastScrollbarVisiable = false;
            this.vScrollBarAdv1.Visible = false;
            this.ShowContent();

            if (this.ControlCountChanged != null)
            {
                this.ControlCountChanged(this, new EventArgs());
            }
        }

        public void Remove(ControlBase value)
        {
            int index = ListControls.IndexOf(value);
            RemoveAt(index);
        }

        public void RemoveAt(int index)
        {
            if ((index < 0) || (index >= ListControls.Count))
            {
                return;
            }

            int offset = ListControls[index].Height * (-1);
            bool lastOneControl = index == (ListControls.Count - 1);
            this.RemoveControl(ListControls[index]);
            this.ListControls.RemoveAt(index);

            this.UpdateScrollBar(offset, lastOneControl);
            ShowContent();

            if (SelectIndex >= ListControls.Count)
            {
                SelectIndex = ListControls.Count - 1;
            }
            else if (SelectIndex < 0)
            {
                SelectIndex = 0;
            }
            else
            {
                SelectIndex = SelectIndex;
            }

            if (this.ControlCountChanged != null)
            {
                this.ControlCountChanged(this, new EventArgs());
            }
        }

        public bool ExChangeControl(int itemIndex1, int itemIndex2)
        {
            if ((itemIndex1 < 0) || (itemIndex1 >= Controls.Count))
            {
                return false;
            }

            if ((itemIndex2 < 0) || (itemIndex2 >= Controls.Count))
            {
                return false;
            }

            return true;
        }

        private void DisableControl(Control value)
        {
            value.Visible = false;
        }

        private void EnableControl(Control value)
        {
            value.Visible = true;
        }

        private void PlaceAddFromFirst(ControlBase value)
        {
            ListControls.Insert(0, value);

            this.UpdateScrollBar(value.Height, 0 == ListControls.Count - 1);
            ShowContent();

            SelectIndex = 0;
        }

        private void PlaceAddFromEnd(ControlBase value)
        {
            ListControls.Add(value);

            this.UpdateScrollBar(value.Height, true);

            ShowContent();

            SelectIndex = ListControls.Count - 1;
        }
 
        void vScrollBarAdv1_Scroll(object sender, System.Windows.Forms.ScrollEventArgs e)
        {
            this.vScrollBarAdv1.Value = e.NewValue;
            ShowContent();
            return;
        }

        void vScrollBarAdv1_MouseEnter(object sender, System.EventArgs e)
        {
            this.Focus();
        }

        void ListControlView_MouseEnter(object sender, System.EventArgs e)
        {
            this.Focus();
        }

        void ListControlView_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            int iValue = this.vScrollBarAdv1.Value;

            int iMax = this.vScrollBarAdv1.Maximum;

            if (iMax < 0)
            {
                iMax = 0;
            }

            iValue -= (e.Delta / 10);

            if (iValue <= 0)
            {
                iValue = 0;
            }
            else if (iValue > iMax)
            {
                iValue = iMax;
            }

            if (this.vScrollBarAdv1.Value == iValue)
            {
                return;
            }

            this.vScrollBarAdv1.Value = iValue;

            ShowContent();
        }

        void ShowContent()
        {
            int wheelValue = vScrollBarAdv1.Value;

            int k = 0;

            if (TotalControlHeight > this.vScrollBarAdv1.ClientSize.Height)
            {
                k = (int)(((double)(TotalControlHeight - this.vScrollBarAdv1.ClientSize.Height) / (double)(this.vScrollBarAdv1.Maximum - this.vScrollBarAdv1.LargeChange + 1)) * wheelValue);
            }

            int position = k;
            int currentHeight = 0;
            int startWh = -1;
            IndexVisibleList.Clear();

            for (int i = 0; i < ListControls.Count; ++i)
            {
                Control myCtl = ListControls[i];
                EnableControl(myCtl);
                currentHeight += myCtl.Size.Height;
                if ((currentHeight >= position) && ((currentHeight - myCtl.Size.Height) <= (position + this.vScrollBarAdv1.ClientSize.Height)))
                {
                    IndexVisibleList.Add(i);
                    EnableControl(myCtl);
                    if (startWh == -1)
                    {
                        startWh = currentHeight - myCtl.Size.Height - position;
                        myCtl.Location = new Point(this.LeftOffset, startWh);
                    }
                    else
                    {
                        myCtl.Location = new Point(this.LeftOffset, startWh);

                    }
                    startWh += myCtl.Size.Height;
                }
                else
                {
                    DisableControl(myCtl);
                }
            }

            Update();
        }


        public void ScrollToIndex(int iIndex)
        {
            if ((iIndex < 0) || (iIndex >= ListControls.Count))
            {
                return;
            }

            if (TotalControlHeight <= vScrollBarAdv1.ClientSize.Height)
            {
                vScrollBarAdv1.Value = 0;
                ShowContent();
                return;
            }

            int CurrentIndexHeight = 0;

            for(int iCnt = 0; iCnt <iIndex; ++iCnt)
            {
                CurrentIndexHeight += ListControls[iCnt].Height;
            }

            if ((TotalControlHeight - CurrentIndexHeight) <= vScrollBarAdv1.ClientSize.Height)
            {
                vScrollBarAdv1.Value = vScrollBarAdv1.Maximum - vScrollBarAdv1.LargeChange + 1;
                ShowContent();
                return;
            }

            vScrollBarAdv1.Value = (int)(((double)(vScrollBarAdv1.Maximum - vScrollBarAdv1.LargeChange + 1) / (TotalControlHeight - vScrollBarAdv1.ClientSize.Height)) * CurrentIndexHeight);
            ShowContent();
        }

        private void vScrollBarAdv1_VisibleChanged(object sender, EventArgs e)
        {
            if (lastScrollbarVisiable != this.vScrollBarAdv1.Visible)
            {
                if (this.vScrollBarAdv1.Visible == true)
                {
                    for (int iCnt = 0; iCnt < ListControls.Count; ++iCnt)
                    {
                        ListControls[iCnt].Width -= this.vScrollBarAdv1.Width;
                    }
                }
                else
                {
                    for (int iCnt = 0; iCnt < ListControls.Count; ++iCnt)
                    {
                        ListControls[iCnt].Width += this.vScrollBarAdv1.Width;
                    }
                }
            }

            lastScrollbarVisiable = this.vScrollBarAdv1.Visible;
            Update();
        }

        private void vScrollBarAdv1_Resize(object sender, EventArgs e)
        {
            this.UpdateScrollBar(this.vScrollBarAdv1.ClientSize.Height - lastScrollbarHeight, false, true);
            this.ShowContent();
            lastScrollbarHeight = this.vScrollBarAdv1.ClientSize.Height;
        }
    }
}
